#pragma once

#include <iostream>
#include <vector>
#include <string>
#include <atomic>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/time.h>

namespace ns_util
{
    class TimeUtil
    {
    public:
        static std::string GetMsTimeStamp()
        {
            struct timeval tv;
            gettimeofday(&tv, nullptr);

            return std::to_string(tv.tv_sec * 1000 + (int)(tv.tv_usec / 1000));
        }
    };
    // 要添加的temp目录
    const std::string temp_path = "temp/";
    class PathUtil
    {
    public:
        static std::string Exe(const std::string &filename)
        {
            return AddSuffix(filename, ".exe");
        }
        static std::string Src(const std::string &filename)
        {
            return AddSuffix(filename, ".cc");
        }
        static std::string CompileError(const std::string &filename)
        {
            return AddSuffix(filename, ".compile_err");
        }
        static std::string Stdin(const std::string &filename)
        {
            return AddSuffix(filename, ".stdin");
        }
        static std::string Stdout(const std::string &filename)
        {
            return AddSuffix(filename, ".stdout");
        }
        static std::string Stderr(const std::string &filename)
        {
            return AddSuffix(filename, ".stderr");
        }

    private:
        static std::string AddSuffix(const std::string &filename, std::string suffix)
        {
            return temp_path + filename + suffix;
        }
    };

    class FileUtil
    {
    public:
        static bool FileIsExists(const std::string &path)
        {
            struct stat st;
            if (stat(path.c_str(), &st) < 0)
            {
                return false;
            }
            return true;
        }
        // 生成唯一文件名
        static std::string UniqueFilename()
        {
            // 毫秒级时间戳+原子性递增得出唯一文件名
            static std::atomic_uint id(0);
            ++id;

            return TimeUtil::GetMsTimeStamp() + "_" + std::to_string(id);
        }
        static bool WriteFile(const std::string &filename, const std::string &code)
        {
            umask(0);
            int fd = open(filename.c_str(), O_CREAT | O_WRONLY, 0644);
            if (fd < 0)
            {
                // create file fail
                return false;
            }

            ssize_t sz = write(fd, code.c_str(), code.size());
            if (sz != code.size())
            {
                // write faile
                close(fd);
                return false;
            }
            close(fd);
            return true;
        }
        static std::string ReadFile(const std::string &filename)
        {
            int fd = open(filename.c_str(), O_RDONLY);
            if (fd < 0)
            {
                return "";
            }
            std::string res;
            char ch;
            while (read(fd, &ch, 1))
            {
                res += ch;
            }
            return std::move(res);
        }
    };
    class StringUtil
    {
    public:
        static void Spilit(const std::string &s, std::vector<std::string> &out, const std::string &sep)
        {
            int size = 0;
            size_t begin = 0;
            while (1)
            {
                size_t pos = s.find(sep, begin);
                if (pos == std::string::npos)
                {
                    out.push_back(s.substr(begin, pos));
                    break;
                }
                out.push_back(s.substr(begin, pos - begin));
                begin = pos + 1;
            }
        }
    };
}
